package com.piper.httputil;

import com.piper.config.ConnectionManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class DefaultHttpProxy {
    private static final Log log = LogFactory.getLog(DefaultHttpProxy.class);
    private static ConnectionManager connectionFactory = new ConnectionManager();
//    private static MethodProcessor methodProcessor = new MethodProcessorBuilder().build();
    private static MethodProcessor methodProcessor = new GetProcessor();

    public static MethodProcessor getMethodProcessor() {
        return methodProcessor;
    }

    public static void setMethodProcessor(MethodProcessor methodProcessor) {
        DefaultHttpProxy.methodProcessor = methodProcessor;
    }

    /**
     * 执行url请求
     */
    public boolean execute(ServletRequest request, ServletResponse response) {
        long beforeTime = System.currentTimeMillis();
        // 根据request创建请求
        HttpRequestBase httpRequest = methodProcessor.doRequest(request);
        if (httpRequest == null) {
            return false;
        }

        // 从连接池中获得HttpClient
        CloseableHttpClient httpClient = connectionFactory.getHttpClient();
        CloseableHttpResponse proxyRes = null;
        try {
            HttpClientContext httpContext = HttpClientContext.create();
            proxyRes = httpClient.execute(httpRequest, httpContext);
            HttpServletResponse servletRes = (HttpServletResponse) response;
            methodProcessor.doResponse(servletRes, proxyRes);
            HttpEntity entity = proxyRes.getEntity();
            if (proxyRes.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
//                OutputStream outputStream = response.getOutputStream();
//                entity.writeTo(outputStream);
//                outputStream.flush();

                //处理html
                if (proxyRes.getFirstHeader("Content-Type").getValue().contains("text/html")) {
                    htmlHandle(servletRes, proxyRes, "sam");
                } else {
                    //处理其他
                    fileHandle(entity, servletRes.getOutputStream());
                }
            } else {
                servletRes.sendError(proxyRes.getStatusLine().getStatusCode());
            }
            long afterTime = System.currentTimeMillis();
            log.debug("-----代理耗时["+(afterTime-beforeTime)+"ms]-----");
        } catch (IOException e) {
            log.error("", e);
            return false;
        }
        return true;
    }

    //处理html
    public void htmlHandle(HttpServletResponse httpServletResponse, CloseableHttpResponse response, String path) {
        ServletOutputStream out = null;
        try {
            String html = EntityUtils.toString(response.getEntity());
            String res = htmlConvert(html, path);

            PrintWriter writer = httpServletResponse.getWriter();
            writer.print(res);
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != response) {
                    response.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //非html直接返回
    public void fileHandle(HttpEntity entity, ServletOutputStream out) {
        try {
            entity.writeTo(out);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 处理html数据里的 js，css，png等的链接地址
     * 方便后面进行转发
     *
     * @param html
     * @return
     */
    String htmlConvert(String html, String path) {

//        html = html.replace("ui-sref=\"{{view.state}}\"","ui-sref=\"{{view.state.substring(2,view.state.length)}}\"");

        StringBuffer str = new StringBuffer(html);

        //path形如： kafka,eureka之类，是yml文件里map属性下的服务名
        path = "/" + path;
        String path2 = path + "/";


        Document doc = Jsoup.parse(html);

        Elements a = doc.select("[href~=#]");
        for (Element e : a) {
            e.removeAttr("href");
        }


        // 找到所有包含src属性，但是链接不以http开头的元素
        Elements src = doc.select("[src~=^(?!http).*$]");
        Elements href = doc.select("[href~=^(?!(http|#)).*$]");
        Elements action = doc.select("[action]");

        for (Element e : src) {
            String link = e.attr("src");
            if (link.startsWith("/")) {
                e.attr("src", path + link);
            } else {
                e.attr("src", path2 + link);
            }
        }
        for (Element e : href) {
            String link = e.attr("href");
            if (link.startsWith("/")) {
                e.attr("href", path + link);
            } else {
                e.attr("href", path2 + link);
            }
        }
        for (Element e : action) {
            String link = e.attr("action");
            if (link.startsWith("/")) {
                e.attr("action", path + link);
            } else {
                e.attr("action", path2 + link);
            }
        }

        return doc.outerHtml();
    }

}
